﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Drawing;

namespace SetResolution
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }



        public class SetMyResolution
        {
            public static void RotateDisplayWindow()
            {
            NativeMethods.ExtendDisplays();

            List<DISPLAY_DEVICE> devices = new List<DISPLAY_DEVICE>();          
            bool error = false;
            //Here I am listing all DisplayDevices (Monitors)
            for (int devId = 0; !error; devId++)
            {
                try
                {
                    DISPLAY_DEVICE device = new DISPLAY_DEVICE();
                    device.cb = Marshal.SizeOf(typeof(DISPLAY_DEVICE));
                    error = !NativeMethods.EnumDisplayDevices(null, devId, ref device, 0);
                    if ((device.StateFlags & DisplayDeviceStateFlags.AttachedToDesktop) == DisplayDeviceStateFlags.AttachedToDesktop)
                    {
                        devices.Add(device);
                    }
                    else {
                        error = true;
                    }
                }
                catch (Exception)
                {
                    error = true;
                }
            }

            foreach (DISPLAY_DEVICE dev in devices)
            {
                if ((dev.StateFlags & DisplayDeviceStateFlags.PrimaryDevice) != DisplayDeviceStateFlags.PrimaryDevice)
                {
                    DEVMODE ndm = NewDevMode();
                    NativeMethods.EnumDisplaySettings(dev.DeviceName, (int)DEVMODE_SETTINGS.ENUM_CURRENT_SETTINGS, ref ndm);
                    CallChangeDisplaySetting(dev, ndm);
                }
            }       
        }


        private static DEVMODE NewDevMode()
        {
            DEVMODE dm = new DEVMODE();
            dm.dmDeviceName = new String(new char[32]);
            dm.dmFormName = new String(new char[32]);
            dm.dmSize = (short)Marshal.SizeOf(dm);
            return dm;
        }

        private static void SwitchWindow(ref DEVMODE dm) {
            int temp = dm.dmPelsHeight;
            dm.dmPelsHeight = dm.dmPelsWidth;
            dm.dmPelsWidth = temp;

            if (dm.dmDisplayOrientation != NativeMethods.DMDO_90)
            {
                dm.dmDisplayOrientation = NativeMethods.DMDO_90;
            }
          // dm.dmPositionX =(Int32)System.Windows.SystemParameters.PrimaryScreenWidth;
            
            //dm.dmPosition.X = (Int32)System.Windows.SystemParameters.PrimaryScreenWidth;

          //  dm.dmPositionX = (int)SystemParameters.PrimaryScreenWidth;
            //// determine new orientation
            //switch (dm.dmDisplayOrientation)
            //{
            //    case NativeMethods.DMDO_DEFAULT:
            //        dm.dmDisplayOrientation = NativeMethods.DMDO_90;
            //        break;
            //    case NativeMethods.DMDO_270:
            //        dm.dmDisplayOrientation = NativeMethods.DMDO_180;
            //        break;
            //    case NativeMethods.DMDO_180:
            //        dm.dmDisplayOrientation = NativeMethods.DMDO_270;
            //        break;
            //    case NativeMethods.DMDO_90:
            //        dm.dmDisplayOrientation = NativeMethods.DMDO_DEFAULT;
            //        break;
            //    default:
            //        // unknown orientation value
            //        // add exception handling here
            //        break;
            //}
        }
        private static void CallChangeDisplaySetting(DISPLAY_DEVICE dev, DEVMODE dm)
        {
            dm.dmDeviceName = dev.DeviceName;
            SwitchWindow(ref dm);
            int ret = NativeMethods.ChangeDisplaySettingsEx(dev.DeviceName, ref dm, (IntPtr)null, 0, IntPtr.Zero);
            if (-2 == ret)
            {
                System.Windows.MessageBox.Show("更新失败");
            }
            //int mret = NativeMethods.ChangeDisplaySettingsEx(null, ref dm, (IntPtr)null, 0, IntPtr.Zero);
            //NativeMethods.SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, 1, IntPtr.Zero, 0);  //启用
        }
        public class NativeMethods
        {
            const uint SPI_SETSCREENSAVEACTIVE = 0x0011;
 
        [DllImport("User32",CharSet=CharSet.Auto)]
        public extern static bool SystemParametersInfoW(uint uiAction, uint uiParam, IntPtr pvParam, uint fWinIni);
 
        
            //SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, 0, IntPtr.Zero, 0);  //禁用
            //...
            //SystemParametersInfoW(SPI_SETSCREENSAVEACTIVE, 1, IntPtr.Zero, 0);  //启用
        


            // PInvoke declaration for EnumDisplaySettings Win32 API
         [DllImport("user32.dll", CharSet = CharSet.Ansi)]
         public static extern int EnumDisplaySettings(
         string lpszDeviceName,
         int iModeNum,
         ref DEVMODE lpDevMode);
            [DllImport("user32.dll")]
            public static extern bool EnumDisplayDevices(string lpDevice, int iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, int dwFlags);//获取屏幕信息

            [DllImport("user32.dll")]
            public static extern int ChangeDisplaySettingsEx(string lpszDeviceName, [In] ref DEVMODE lpDevMode, IntPtr hwnd, int dwFlags, IntPtr lParam); //设置横竖屏

            [DllImport("user32.dll", CharSet = CharSet.Unicode)]
            private static extern long SetDisplayConfig(uint numPathArrayElements,
            IntPtr pathArray, uint numModeArrayElements, IntPtr modeArray, uint flags);  //用于设置复制、扩展屏幕

            UInt32 SDC_TOPOLOGY_INTERNAL = 0x00000001;
            UInt32 SDC_TOPOLOGY_CLONE = 0x00000002;
            static UInt32 SDC_TOPOLOGY_EXTEND = 0x00000004;
            UInt32 SDC_TOPOLOGY_EXTERNAL = 0x00000008;
            static UInt32 SDC_APPLY = 0x00000080;

            public static void ExtendDisplays()
            {
                SetDisplayConfig(0, IntPtr.Zero, 0, IntPtr.Zero, (SDC_APPLY | SDC_TOPOLOGY_EXTEND));
            }
            // add more functions as needed ??

            // constants
            public const int ENUM_CURRENT_SETTINGS = -1;
            public const int DMDO_DEFAULT = 0;
            public const int DMDO_90 = 1;
            public const int DMDO_180 = 2;
            public const int DMDO_270 = 3;
            // add more constants as needed ??
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct DEVMODE
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string dmDeviceName;

            public short dmSpecVersion;
            public short dmDriverVersion;
            public short dmSize;
            public short dmDriverExtra;
            public int dmFields;
            public int dmPositionX;
            public int dmPositionY;
           // public Point dmPosition;
            public int dmDisplayOrientation;
            public int dmDisplayFixedOutput;
            public short dmColor;
            public short dmDuplex;
            public short dmYResolution;
            public short dmTTOption;
            public short dmCollate;

            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string dmFormName;

            public short dmLogPixels;
            public short dmBitsPerPel;
            public int dmPelsWidth;
            public int dmPelsHeight;
            public int dmDisplayFlags;
            public int dmDisplayFrequency;
            public int dmICMMethod;
            public int dmICMIntent;
            public int dmMediaType;
            public int dmDitherType;
            public int dmReserved1;
            public int dmReserved2;
            public int dmPanningWidth;
            public int dmPanningHeight;
        };

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct DISPLAY_DEVICE
        {
            [MarshalAs(UnmanagedType.U4)]
            public int cb;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            public string DeviceName;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string DeviceString;
            [MarshalAs(UnmanagedType.U4)]
            public DisplayDeviceStateFlags StateFlags;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string DeviceID;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
            public string DeviceKey;
        }

        [Flags()]
        public enum DisplayDeviceStateFlags : int
        {
            /// <summary>The device is part of the desktop.</summary>
            AttachedToDesktop = 0x1,
            MultiDriver = 0x2,
            /// <summary>The device is part of the desktop.</summary>
            PrimaryDevice = 0x4,
            /// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
            MirroringDriver = 0x8,
            /// <summary>The device is VGA compatible.</summary>
            VGACompatible = 0x10,
            /// <summary>The device is removable; it cannot be the primary display.</summary>
            Removable = 0x20,
            /// <summary>The device has more display modes than its output devices support.</summary>
            ModesPruned = 0x8000000,
            Remote = 0x4000000,
            Disconnect = 0x2000000
        }

        public enum DeviceFlags
        {
            CDS_FULLSCREEN = 0x4,
            CDS_GLOBAL = 0x8,
            CDS_NORESET = 0x10000000,
            CDS_RESET = 0x40000000,
            CDS_SET_PRIMARY = 0x10,
            CDS_TEST = 0x2,
            CDS_UPDATEREGISTRY = 0x1,
            CDS_VIDEOPARAMETERS = 0x20,
        }

        public enum DEVMODE_SETTINGS
        {
            ENUM_CURRENT_SETTINGS = (-1),
            ENUM_REGISTRY_SETTINGS = (-2),
        }
        }

        private void ChangeResolution_Click(object sender, RoutedEventArgs e)
        {
            SetMyResolution.RotateDisplayWindow();
            //int monitorcount = SystemInformation.MonitorCount;

            //Rectangle[] screenRect = new Rectangle[monitorcount];
            //Screen[] sc = Screen.AllScreens;
            //for (int i = 0; i < monitorcount; i++)
            //{
            //    screenRect[i] = sc[i].WorkingArea;
            //}
    
        }
    }
}
